import java.util.HashSet;
import java.util.Iterator;
import java.util.Vector;


/**
 * rsm ()Rasmus scheduling Method) is a Class for computing all the actions starting times.
 *it Takes the greedy approach by computing an actions starting time only once,
 *that means, it never changes the starting time for an action once it computed it once.  
 */
public class Rsm {			
	public static HashSet<Action> rpm(Plan plan) {

		/**
		 *ready includes the actions with computed starting times
		 *in the beginning this only includes the start action (with start time at 0)
		 */
		HashSet<Action> ready = new HashSet<Action>();

		/**
		 *unready includes the actions that hasn't got their start time jet.
		 *in the beginning this is all actions except the start action. 
		 */
		HashSet<Action> unReady = new HashSet<Action>();
		
		for(Action a: plan.getActions()){
			unReady.add(a);
		}
		
		unReady.remove(plan.start());
		ready.add(plan.start());
		
		HashSet<OrderingConstraint> ocs = plan.getOrderingConstraints();
		boolean ok;
		Iterator<Action> unReadyIterator = unReady.iterator();
		Action b;
		/**
		 *Pseudo code for the following while loop:
		 *while there is still an action that hasn't got its time computed
		 *for all unready actions where
		 *		all orderingConstrainted actions are in ready
		 *			compute those actions action-time
		 * 
		 */	
		while(!unReady.isEmpty()){
			
			unReadyIterator = unReady.iterator();
			
			while (unReadyIterator.hasNext()) {
				b = unReadyIterator.next();
				
				ok = true;
				
				for (OrderingConstraint o : ocs) {
					if (o.getAfter().equals(b) && !ready.contains(o.getBefore())) {
						ok = false;
					}
				}
				
				if(ok) {
					int maxTime =0;
					for (OrderingConstraint o : ocs) {
						if (o.getAfter().equals(b)) {
							if (maxTime < o.getBefore().getStartTime() + o.getBefore().getDuration()){
								maxTime = o.getBefore().getStartTime() + o.getBefore().getDuration();
							}
						
						}
						ok = false;
					}
					b.setStartTime(maxTime);
					
					setParTime(b,ready);
					ready.add(b);
					
					unReadyIterator.remove();
				}
			}
		}
		return ready;
	}
			
	/**
	 * Check if an action a, is parallelizable with the actions 
	 * that intersect with the action in the timeline.   
	 * if that is the case, the action keeps its starting time
	 * otherwise its earliest starting time is set to the time all
	 * the not parralelizable actions has ended. 
	 *  
	 * @param a the action that will get its start time computed 
	 * @param readyActions the actions that have their starting times computed
	 */		
	private static void setParTime(Action a, HashSet<Action> readyActions) {
			Vector<Resource> resources = new Vector<Resource>(Agent.resources);
			//int readyEndTime = 0;
			int startTime = a.getStartTime();
			//int endTime = startTime + a.getDuration();
			for (Action ready : readyActions) {
				//isParallelizable() should check how much of a resource
				//there is in the period we want to ad the action.
				//And then check if the adding of the action produce 
				//a negative amount of any recourse 
				// 
		
				//readyEndTime = ready.getLatestStartTime()+ready.getDuration();
				
				//if (!ready.isParallelizable()
				if (
						((ready.getStartTime() <= a.getStartTime()
							&& ready.getStartTime()+ready.getDuration() > a.getStartTime())
							||
							(ready.getStartTime() > a.getStartTime() 
							&& ready.getStartTime() <= a.getStartTime() + a.getDuration()) 
						)	// check that all required resources are free 
																							// in the current timeslot
					){
					
					/* remove all resources used by ready */
					for (Resource r : ready.getResources()) {
						resources.remove(r);
					}
					
					//&& (readyEndTime > startTime)&& ready.getLatestStartTime() < endTime){
					//OBS need more checks
					if (!resources.containsAll(a.getResources())) {
						startTime = (ready.getStartTime()
								+ ready.getDuration());
						//endTime = startTime +  a.getDuration();
						//loook out for endles loop!!
						// TODO: do not move further ahead if a resource becomes available from another action that ends earlier
						a.setStartTime(startTime);
						
						setParTime(a, readyActions);
						//to avoid setting latest start time to an old start time value break 
					}
					
					System.out.println("----");
					System.out.println(a + " vs " + ready);
					System.out.println("a needs: " + a.getResources());
					System.out.println("ready uses: " + ready.getResources());
					System.out.println("left for a: " + resources);
					System.out.println("sufficient resources? " + resources.containsAll(a.getResources()));
				}
			}
	} 
}
	


